/**
 *File: Directory.h
 *Authors: Tim and Diane
 *Created Oct 2012
 */

#ifndef _DIRECTORY_H
#define _DIRECTORY_H


#include <stdio.h>
#include <stdlib.h>
//#include <direct.h>
//#include "BlockGroup.h"
#include <sys/types.h>
#include <errno.h>
#include <string>
#include "DirectoryEntry.h"
#include "Disk.h"

#include <vector>
using namespace std;

/**
 * Provides a single-layer or flat directory.
 * @author Timothy Millard <mill4138@d.umn.edu>
 * @author Diane Weiss     <weis0258@d.umn.edu>
 *
 */

class Directory {
//class Directory {
public:

  /**
   * Open and read directory. Copies directory data from Disk to RAM to be played with.
   * A directory IS A BlockGroup.
   *
   * @param td The Disk that contains the Directory.
   * @param createDirectory if true, create the directory
   */
  Directory(Disk* td, bool createDirectory);

  /**
   * Destroys RAM based representation of Directory.
   * Make sure to call flushdir() before using this destructor;
   * otherwise, you might lose data.
   */
  ~Directory();

  /** 
   * Searches the directory for a matching entry by name. DirectoryEntrys
   * are returned as an array.
   * TODO: Allow multiple file names to be searched
   * (maybe with an array of strings).
   * 
   * @param result_set Result Set of DirectoryEntry's.
   * @param search_key What we're looking for. If blank, will show all entries.
   * @return the number of directory entries selected, else -1 if error
   */
  int scandir(vector<DirectoryEntry> &result_set, string search_key);

  /**
   * Searches directory for search_key.
   * TODO: Allow wild cards in filename.
   * @return The DirectoryEntry
   * @param searchkey What we're looking for.
   */

  DirectoryEntry* scandir(string search_key);

  /** 
   * Writes the entries of the directory to disk. After modifying a
   * DirectoryEntry that is within this directory,
   * this should be called so that they are
   * flushed/written/committed to disk.
   *
   * Retains RAM-Based data structure (does not delete them in RAM). Free up or
   * return to FreeList, the BlockGroup with which we currently represent the
   * directory. Then, allocate new BlockGroup with sufficient blocks.
   * Write out directory blocks.
   * Re-write Master Block to point to this Directory.
   *
   * @return TRUE if successful
   */
  bool flushdir();

  /** 
   * Add a directory entry to this directory in RAM.
   *
   * @param entry DirectoryEntry to add to this Directory.
   * @return TRUE if success
   */
  bool add_entry(const DirectoryEntry entry);

  /** 
   * Deletes a directory entry from RAM
   *
   * @param search_key Name of DirectoryEntry to delete from Directory.
   * @return TRUE if success.
   */
  bool delete_entry(string search_key);
  
  
  /** 
   * Rename a directory entry in RAM
   *
   * @param new_name New name to call the DirectoryEntry referenced by old_name.
   * @param old_name Current name of the DirectoryEntry that should be renamed.
   * @return TRUE iff the filename was changed. 
   */
  bool rename_entry(string new_name, string old_name);

  /**
   * Find the number of DirectoryEntrys in RAM.
   * @return Number of DirectoryEntry objects in RAM for this Directory.
   */
  int get_num_DirectoryEntry();
  
  
  /**
   * Finds the Block number of a File Control Block (FCB) based on a filename.
   * Note, "there is no need to allocate FCB for a file in this lab."
   * We will simply return the Block number of where it ought to be.
   *
   * @return Block number of FCB, zero (0) on error.
   * @param filename Filename to find the FCB for.
   */
  unsigned int get_FCB(string search_key);

  /**
   * Allows the class to be tested.
   */
  static void Test();

  private:
  /**
   * BlockGroup for Directory
   */

    Disk *the_disk;

  /**
   * Directory Entry STL vector
   */
  vector<DirectoryEntry> de_list;

  /**
   * The Freelist
   */
  FreeList *the_free_list;

  BlockGroup *dir_block_group; 

};
#endif
